package internal

import (
	"context"
	"errors"
	"fmt"
	"gitee.com/zhuoyue6/wecom_msg/config"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"sync"
)

// ==================== 基础仓储 ====================

const DefaultLogLevel = logger.Silent

type BaseRepo[T any] struct {
	Db         *gorm.DB
	Ctx        context.Context
	LogMode    logger.LogLevel
	muLog      sync.Mutex
	muCache    sync.Mutex
	cache      *sync.Map // 缓存存储
	primaryKey string    // model 表主键
}

func NewBaseRepository[T any](ctx context.Context) *BaseRepo[T] {
	return &BaseRepo[T]{
		Db:         config.DB,
		Ctx:        ctx,
		LogMode:    DefaultLogLevel,
		cache:      new(sync.Map),
		primaryKey: "id",
	}
}

// SetPrimaryKey 设置主键
func (r *BaseRepo[T]) SetPrimaryKey(k string) *BaseRepo[T] {
	r.primaryKey = k
	return r
}

// SetLogMode 动态设置日志模式（线程安全）
func (r *BaseRepo[T]) SetLogMode(level logger.LogLevel) *BaseRepo[T] {
	r.muLog.Lock()
	defer r.muLog.Unlock()
	r.LogMode = level
	r.Db.Logger = r.Db.Logger.LogMode(level)
	return r
}

// SetDefaultLogLevel 设置默认日志级别
func (r *BaseRepo[T]) SetDefaultLogLevel() *BaseRepo[T] {
	r.SetLogMode(DefaultLogLevel)
	return r
}

// DebugDB 带调试模式的 DB 实例（用于最后一次重试）
func (r *BaseRepo[T]) DebugDB() *gorm.DB {
	return r.Db.Debug().Session(&gorm.Session{
		Logger: logger.Default.LogMode(logger.Info),
	})
}

func (r *BaseRepo[T]) GetByPK(id int64) (*T, error) {
	// 1. 优先读缓存
	if val, ok := r.cache.Load(id); ok {
		return val.(*T), nil // 命中缓存直接返回
	}

	// 2. 防击穿锁 + 双重检查
	r.muCache.Lock()
	defer r.muCache.Unlock()
	if val, ok := r.cache.Load(id); ok {
		return val.(*T), nil
	}

	// 3. 查询数据库
	var model T
	if err := r.Db.First(&model, fmt.Sprintf("%s = %d", r.primaryKey, id)).Error; err != nil {
		return nil, err
	}

	// 4. 写入缓存
	r.cache.Store(id, &model)
	return &model, nil
}

func (r *BaseRepo[T]) SetToPK(id int64, info T) bool {
	r.muCache.Lock()
	defer r.muCache.Unlock()
	r.cache.Store(id, &info)
	return true
}

// ClearPK 清除指定主键的缓存
func (r *BaseRepo[T]) ClearPK(id int64) bool {
	r.muCache.Lock()
	defer r.muCache.Unlock()
	r.cache.Delete(id)
	return true
}

// ==================== 用户仓储 ====================

type WorkWechatUserRepo struct {
	*BaseRepo[WecomUser]
	useridMap *sync.Map // 并发安全 userid 缓存: map[string]*WecomUser
	aliasMap  *sync.Map // 并发安全 alias 缓存: map[string]*WecomUser
}

// NewWorkWechatUserRepo 创建企业微信用户仓库实例
func NewWorkWechatUserRepo(ctx context.Context) *WorkWechatUserRepo {
	return &WorkWechatUserRepo{
		BaseRepo: NewBaseRepository[WecomUser](ctx).SetPrimaryKey("id"),
		aliasMap: new(sync.Map),
	}
}

// GetByAlias 根据 Alias 获取用户信息（带缓存）
func (r *WorkWechatUserRepo) GetByAlias(alias string) (*WecomUser, error) {
	// 1. 先查缓存
	if val, ok := r.aliasMap.Load(alias); ok {
		return val.(*WecomUser), nil
	}

	// 2. 查数据库
	var user WecomUser
	err := r.Db.WithContext(r.Ctx).Where("alias = ?", alias).First(&user).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}

	// 3. 写入缓存
	r.aliasMap.Store(alias, &user)
	return &user, nil
}

func (r *WorkWechatUserRepo) Create(user *WecomUser) error {
	err := r.Db.WithContext(r.Ctx).Create(user).Error
	if err != nil {
		return err
	}

	return nil
}

func (r *WorkWechatUserRepo) Update(user *WecomUser) error {
	err := r.Db.WithContext(r.Ctx).Save(user).Error
	if err != nil {
		return err
	}
	return nil
}

// ClearAllCache 清理所有缓存
func (r *WorkWechatUserRepo) ClearAllCache() {
	r.aliasMap = new(sync.Map)
}

// ==================== 消息记录仓储 ====================

// WecomMessageRecordRepo 企业微信消息记录仓储
type WecomMessageRecordRepo struct {
	ctx context.Context
	db  *gorm.DB
}

// NewWecomMessageRecordRepo 创建企业微信消息记录仓储
func NewWecomMessageRecordRepo(ctx context.Context) *WecomMessageRecordRepo {
	return &WecomMessageRecordRepo{
		ctx: ctx,
		db:  config.DB,
	}
}

// Create 创建消息记录
func (r *WecomMessageRecordRepo) Create(record *WecomMessageRecord) error {
	return r.db.Create(record).Error
}

// Update 更新消息记录
func (r *WecomMessageRecordRepo) Update(record *WecomMessageRecord) error {
	return r.db.Save(record).Error
}
